

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
  <link rel="icon" href="/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
    <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="dayu">
  <meta name="keywords" content="">
  
    <meta name="description" content="大事件项目(NodeJS)1.初始化1.1 创建项目 新建 api_server 文件夹作为项目根目录，并在项目根目录中运行如下的命令，初始化包管理配置文件： 1npm init -y 运行如下的命令，安装特定版本的 express： 1npm i express@4.17.1 在项目根目录中新建 app.js 作为整个项目的入口文件，并初始化如下的代码： 1234567891011&#x2F;&#x2F; 导入 e">
<meta property="og:type" content="article">
<meta property="og:title" content="HeadLine">
<meta property="og:url" content="http://dayu.com/2022/11/30/HeadLine/index.html">
<meta property="og:site_name" content="Dayu">
<meta property="og:description" content="大事件项目(NodeJS)1.初始化1.1 创建项目 新建 api_server 文件夹作为项目根目录，并在项目根目录中运行如下的命令，初始化包管理配置文件： 1npm init -y 运行如下的命令，安装特定版本的 express： 1npm i express@4.17.1 在项目根目录中新建 app.js 作为整个项目的入口文件，并初始化如下的代码： 1234567891011&#x2F;&#x2F; 导入 e">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://pic.imgdb.cn/item/63883b8f16f2c2beb1cda8b7.jpg">
<meta property="og:image" content="https://pic.imgdb.cn/item/63883c2116f2c2beb1ce5f35.jpg">
<meta property="og:image" content="https://pic.imgdb.cn/item/63883c4216f2c2beb1ce8193.jpg">
<meta property="og:image" content="https://pic.imgdb.cn/item/6388386716f2c2beb1c9ad03.jpg">
<meta property="article:published_time" content="2022-11-30T15:27:36.000Z">
<meta property="article:modified_time" content="2023-09-13T02:49:44.407Z">
<meta property="article:author" content="dayu">
<meta property="article:tag" content="node">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://pic.imgdb.cn/item/63883b8f16f2c2beb1cda8b7.jpg">
  
  
    <meta name="referrer" content="no-referrer-when-downgrade">
  
  
  <title>HeadLine - Dayu</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  



  
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_3846514_kabxni94auf.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/shubiao.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/gundongtiao.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"dayu.com","root":"/","version":"1.9.3","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  

  

  

  

  

  

  

  



  
<meta name="generator" content="Hexo 5.4.2"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Dayu</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives">
                <i class="iconfont icon-books"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories">
                <i class="iconfont icon-th-large"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                友链
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item dropdown">
              <a class="nav-link dropdown-toggle" target="_self" href="javascript:;" role="button"
                 data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                <i class="iconfont icon-book"></i>
                文档
              </a>
              <div class="dropdown-menu" aria-labelledby="navbarDropdown">
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/">
                    
                    主题博客
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/guide/">
                    
                    配置指南
                  </a>
                
                  
                  
                  
                  <a class="dropdown-item" target="_blank" rel="noopener" href="https://hexo.fluid-dev.com/docs/icon/">
                    
                    图标用法
                  </a>
                
              </div>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/default.png') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="HeadLine"></span>
          
        </div>

        
          
  <div class="mt-3">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-author" aria-hidden="true"></i>
        dayu
      </span>
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2022-11-30 23:27" pubdate>
           2022 年 11 月 30 日 , 晚上 11:27 , 星期三
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          <!-- compatible with older versions-->
          26k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          <!-- compatible with older versions-->
          219 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">HeadLine</h1>
            
            
              <div class="markdown-body">
                
                <h1 id="大事件项目-NodeJS"><a href="#大事件项目-NodeJS" class="headerlink" title="大事件项目(NodeJS)"></a>大事件项目(NodeJS)</h1><h2 id="1-初始化"><a href="#1-初始化" class="headerlink" title="1.初始化"></a>1.初始化</h2><h3 id="1-1-创建项目"><a href="#1-1-创建项目" class="headerlink" title="1.1 创建项目"></a>1.1 创建项目</h3><ul>
<li><p>新建 <code>api_server</code> 文件夹作为项目根目录，并在项目根目录中运行如下的命令，初始化包管理配置文件：</p>
<figure class="highlight coffeescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs coffeescript"><span class="hljs-built_in">npm</span> init -y<br></code></pre></td></tr></table></figure></li>
<li><p>运行如下的命令，安装特定版本的 <code>express</code>：</p>
<figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">npm</span> i express@<span class="hljs-number">4</span>.<span class="hljs-number">17</span>.<span class="hljs-number">1</span><br></code></pre></td></tr></table></figure></li>
<li><p>在项目根目录中新建 <code>app.js</code> 作为整个项目的入口文件，并初始化如下的代码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入 express 模块</span><br><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-comment">// 创建 express 的服务器实例</span><br><span class="hljs-keyword">const</span> app = <span class="hljs-title function_">express</span>()<br><br><span class="hljs-comment">// write your code here...</span><br><br><span class="hljs-comment">// 调用 app.listen 方法，指定端口号并启动web服务器</span><br>app.<span class="hljs-title function_">listen</span>(<span class="hljs-number">3007</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;api server running at http://127.0.0.1:3007&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ul>
<h3 id="1-2-配置-cors-跨域"><a href="#1-2-配置-cors-跨域" class="headerlink" title="1.2 配置 cors 跨域"></a>1.2 配置 cors 跨域</h3><ul>
<li><p>运行如下的命令，安装 <code>cors</code> 中间件：</p>
<figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">npm</span> i cors@<span class="hljs-number">2</span>.<span class="hljs-number">8</span>.<span class="hljs-number">5</span><br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中导入并配置 <code>cors</code> 中间件：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入 cors 中间件</span><br><span class="hljs-keyword">const</span> cors = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;cors&#x27;</span>)<br><span class="hljs-comment">// 将 cors 注册为全局中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-title function_">cors</span>())<br></code></pre></td></tr></table></figure></li>
</ul>
<h3 id="1-3-配置解析表单数据的中间件"><a href="#1-3-配置解析表单数据的中间件" class="headerlink" title="1.3 配置解析表单数据的中间件"></a>1.3 配置解析表单数据的中间件</h3><p>通过如下的代码，配置解析 <code>application/x-www-form-urlencoded</code> 格式的表单数据的中间件：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">app.<span class="hljs-title function_">use</span>(express.<span class="hljs-title function_">urlencoded</span>(&#123; <span class="hljs-attr">extended</span>: <span class="hljs-literal">false</span> &#125;))<br></code></pre></td></tr></table></figure>

<h3 id="1-4-初始化路由相关的文件夹"><a href="#1-4-初始化路由相关的文件夹" class="headerlink" title="1.4 初始化路由相关的文件夹"></a>1.4 初始化路由相关的文件夹</h3><ul>
<li><p>在项目根目录中，新建 <code>router</code> 文件夹，用来存放所有的<code>路由</code>模块</p>
<p>路由模块中，只存放客户端的请求与处理函数之间的映射关系</p>
</li>
<li><p>在项目根目录中，新建 <code>router_handler</code> 文件夹，用来存放所有的 <code>路由处理函数模块</code></p>
<p>路由处理函数模块中，专门负责存放每个路由对应的处理函数</p>
</li>
</ul>
<h3 id="1-5-初始化用户路由模块"><a href="#1-5-初始化用户路由模块" class="headerlink" title="1.5 初始化用户路由模块"></a>1.5 初始化用户路由模块</h3><ul>
<li><p>在 <code>router</code> 文件夹中，新建 <code>user.js</code> 文件，作为用户的路由模块，并初始化代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-comment">// 创建路由对象</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 注册新用户</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/reguser&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;reguser OK&#x27;</span>)<br>&#125;)<br><br><span class="hljs-comment">// 登录</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/login&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;login OK&#x27;</span>)<br>&#125;)<br><br><span class="hljs-comment">// 将路由对象共享出去</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中，导入并使用 <code>用户路由模块</code> ：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入并注册用户路由模块</span><br><span class="hljs-keyword">const</span> userRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./router/user&#x27;</span>)<br>app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/api&#x27;</span>, userRouter)<br></code></pre></td></tr></table></figure></li>
</ul>
<h3 id="抽离用户路由模块中的处理函数"><a href="#抽离用户路由模块中的处理函数" class="headerlink" title="抽离用户路由模块中的处理函数"></a>抽离用户路由模块中的处理函数</h3><p><code>目的：为了保证 路由模块 的纯粹性，所有的 路由处理函数，必须抽离到对应的 路由处理函数模块 中</code></p>
<ul>
<li><p>在 <code>/router_handler/user.js</code> 中，使用 <code>exports</code> 对象，分别向外共享如下两个 <code>路由处理函数</code> ：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 在这里定义和用户相关的路由处理函数，供 /router/user.js 模块进行调用</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-comment">// 注册用户的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">regUser</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;reguser OK&#x27;</span>)<br>&#125;<br><br><span class="hljs-comment">// 登录的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">login</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;login OK&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>将 <code>/router/user.js</code> 中的代码修改为如下结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 导入用户路由处理函数模块</span><br><span class="hljs-keyword">const</span> userHandler = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../router_handler/user&#x27;</span>)<br><br><span class="hljs-comment">// 注册新用户</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/reguser&#x27;</span>, userHandler.<span class="hljs-property">regUser</span>)<br><span class="hljs-comment">// 登录</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/login&#x27;</span>, userHandler.<span class="hljs-property">login</span>)<br><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
</ul>
<h2 id="2-登录注册"><a href="#2-登录注册" class="headerlink" title="2. 登录注册"></a>2. 登录注册</h2><h3 id="2-1-新建-ev-users-表"><a href="#2-1-新建-ev-users-表" class="headerlink" title="2.1 新建 ev_users 表"></a>2.1 新建 ev_users 表</h3><p>在 <code>my_db_01</code> 数据库中，新建 <code>ev_users</code> 表如下：</p>
<p><img src="https://pic.imgdb.cn/item/63883b8f16f2c2beb1cda8b7.jpg" srcset="/img/loading.gif" lazyload></p>
<h3 id="2-2-安装并配置-mysql-模块"><a href="#2-2-安装并配置-mysql-模块" class="headerlink" title="2.2 安装并配置 mysql 模块"></a>2.2 安装并配置 mysql 模块</h3><p>在 API 接口项目中，需要安装并配置 <code>mysql</code> 这个第三方模块，来连接和操作 MySQL 数据库</p>
<ul>
<li><p>运行如下命令，安装 <code>mysql</code> 模块：</p>
<figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">npm</span> i mysql@<span class="hljs-number">2</span>.<span class="hljs-number">18</span>.<span class="hljs-number">1</span><br></code></pre></td></tr></table></figure></li>
<li><p>在项目根目录中新建 <code>/db/index.js</code> 文件，在此自定义模块中创建数据库的连接对象：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> mysql = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;mysql&#x27;</span>)<br><br><span class="hljs-comment">// 创建数据库连接对象</span><br><span class="hljs-keyword">const</span> db = mysql.<span class="hljs-title function_">createPool</span>(&#123;<br>  <span class="hljs-attr">host</span>: <span class="hljs-string">&#x27;127.0.0.1&#x27;</span>,<br>  <span class="hljs-attr">user</span>: <span class="hljs-string">&#x27;root&#x27;</span>,<br>  <span class="hljs-attr">password</span>: <span class="hljs-string">&#x27;admin123&#x27;</span>,<br>  <span class="hljs-attr">database</span>: <span class="hljs-string">&#x27;my_db_01&#x27;</span>,<br>&#125;)<br><br><span class="hljs-comment">// 向外共享 db 数据库连接对象</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = db<br></code></pre></td></tr></table></figure></li>
</ul>
<h3 id="2-3-注册"><a href="#2-3-注册" class="headerlink" title="2.3 注册"></a>2.3 注册</h3><h4 id="2-3-0-实现步骤"><a href="#2-3-0-实现步骤" class="headerlink" title="2.3.0 实现步骤"></a>2.3.0 实现步骤</h4><ul>
<li>检测表单数据是否合法</li>
<li>检测用户名是否被占用</li>
<li>对密码进行加密处理</li>
<li>插入新用户</li>
</ul>
<h4 id="2-3-1-检测表单数据是否合法"><a href="#2-3-1-检测表单数据是否合法" class="headerlink" title="2.3.1 检测表单数据是否合法"></a>2.3.1 检测表单数据是否合法</h4><ul>
<li><p>判断用户名和密码是否为空</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 接收表单数据</span><br><span class="hljs-keyword">const</span> userinfo = req.<span class="hljs-property">body</span><br><span class="hljs-comment">// 判断数据是否合法</span><br><span class="hljs-keyword">if</span> (!userinfo.<span class="hljs-property">username</span> || !userinfo.<span class="hljs-property">password</span>) &#123;<br>  <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123; <span class="hljs-attr">status</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;用户名或密码不能为空！&#x27;</span> &#125;)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ul>
<h4 id="2-3-2-检测用户名是否被占用"><a href="#2-3-2-检测用户名是否被占用" class="headerlink" title="2.3.2 检测用户名是否被占用"></a>2.3.2 检测用户名是否被占用</h4><ul>
<li><p>导入数据库操作模块：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../db/index&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>定义 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select * from ev_users where username=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>执行 SQL 语句并根据结果判断用户名是否被占用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, [userinfo.<span class="hljs-property">username</span>], <span class="hljs-keyword">function</span> (<span class="hljs-params">err, results</span>) &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) &#123;<br>    <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123; <span class="hljs-attr">status</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">message</span>: err.<span class="hljs-property">message</span> &#125;)<br>  &#125;<br>  <span class="hljs-comment">// 用户名被占用</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> &gt; <span class="hljs-number">0</span>) &#123;<br>    <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123;<br>      <span class="hljs-attr">status</span>: <span class="hljs-number">1</span>,<br>      <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;用户名被占用，请更换其他用户名！&#x27;</span>,<br>    &#125;)<br>  &#125;<br>  <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> 用户名可用，继续后续流程...</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ul>
<h3 id="2-3-3-对密码进行加密处理"><a href="#2-3-3-对密码进行加密处理" class="headerlink" title="2.3.3 对密码进行加密处理"></a>2.3.3 对密码进行加密处理</h3><p>为了保证密码的安全性，不建议在数据库以 <code>明文</code> 的形式保存用户密码，推荐对密码进行 <code>加密存储</code></p>
<p>在当前项目中，使用 <code>bcryptjs</code> 对用户密码进行加密，优点：</p>
<ul>
<li>加密之后的密码，<strong>无法被逆向破解</strong></li>
<li>同一明文密码多次加密，得到的<strong>加密结果各不相同</strong>，保证了安全性</li>
</ul>
<ol>
<li><p>运行如下命令，安装指定版本的 <code>bcryptjs</code> ：</p>
<figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">npm</span> i bcryptjs@<span class="hljs-number">2</span>.<span class="hljs-number">4</span>.<span class="hljs-number">3</span><br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/user.js</code> 中，导入 <code>bcryptjs</code> ：</p>
<figure class="highlight isbl"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs isbl"><span class="hljs-variable">const</span> <span class="hljs-variable">bcrypt</span> = <span class="hljs-function"><span class="hljs-title">require</span>(<span class="hljs-string">&#x27;bcryptjs&#x27;</span>)</span><br></code></pre></td></tr></table></figure></li>
<li><p>在注册用户的处理函数中，确认用户名可用之后，调用 <code>bcrypt.hashSync(明文密码, 随机盐的长度)</code> 方法，对用户的密码进行加密处理：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 对用户的密码,进行 bcrype 加密，返回值是加密之后的密码字符串</span><br>userinfo.<span class="hljs-property">password</span> = bcrypt.<span class="hljs-title function_">hashSync</span>(userinfo.<span class="hljs-property">password</span>, <span class="hljs-number">10</span>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="2-3-4-插入新用户"><a href="#2-3-4-插入新用户" class="headerlink" title="2.3.4 插入新用户"></a>2.3.4 插入新用户</h3><ol>
<li><p>定义插入用户的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">&#x27;insert into ev_users set ?&#x27;</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句，插入新用户：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(<br>  sql,<br>  &#123; <span class="hljs-attr">username</span>: userinfo.<span class="hljs-property">username</span>, <span class="hljs-attr">password</span>: userinfo.<span class="hljs-property">password</span> &#125;,<br>  <span class="hljs-keyword">function</span> (<span class="hljs-params">err, results</span>) &#123;<br>    <span class="hljs-comment">// 执行 SQL 语句失败</span><br>    <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123; <span class="hljs-attr">status</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">message</span>: err.<span class="hljs-property">message</span> &#125;)<br>    <span class="hljs-comment">// SQL 语句执行成功，但影响行数不为 1</span><br>    <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) &#123;<br>      <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">send</span>(&#123; <span class="hljs-attr">status</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;注册用户失败，请稍后再试！&#x27;</span> &#125;)<br>    &#125;<br>    <span class="hljs-comment">// 注册成功</span><br>    res.<span class="hljs-title function_">send</span>(&#123; <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;注册成功！&#x27;</span> &#125;)<br>  &#125;<br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="2-4-优化-res-send-代码"><a href="#2-4-优化-res-send-代码" class="headerlink" title="2.4 优化 res.send() 代码"></a>2.4 优化 res.send() 代码</h3><p>在处理函数中，需要多次调用 <code>res.send()</code> 向客户端响应 处理失败 的结果，为了简化代码，可以手动封装一个 <code>res.cc()</code> 函数</p>
<p>在 <code>app.js</code> 中，所有路由之前，声明一个全局中间件，为 res 对象挂载一个 <code>res.cc()</code> 函数 ：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 响应数据的中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">req, res, next</span>) &#123;<br>  <span class="hljs-comment">// status = 0 为成功； status = 1 为失败； 默认将 status 的值设置为 1，方便处理失败的情况</span><br>  res.<span class="hljs-property">cc</span> = <span class="hljs-keyword">function</span> (<span class="hljs-params">err, status = <span class="hljs-number">1</span></span>) &#123;<br>    res.<span class="hljs-title function_">send</span>(&#123;<br>      <span class="hljs-comment">// 状态</span><br>      status,<br>      <span class="hljs-comment">// 状态描述，判断 err 是 错误对象 还是 字符串</span><br>      <span class="hljs-attr">message</span>: err <span class="hljs-keyword">instanceof</span> <span class="hljs-title class_">Error</span> ? err.<span class="hljs-property">message</span> : err,<br>    &#125;)<br>  &#125;<br>  <span class="hljs-title function_">next</span>()<br>&#125;)<br></code></pre></td></tr></table></figure>

<h3 id="2-5-优化表单数据验证"><a href="#2-5-优化表单数据验证" class="headerlink" title="2.5 优化表单数据验证"></a>2.5 优化表单数据验证</h3><p>表单验证的原则：前端验证为辅，后端验证为主，后端永远不要相信前端提交过来的任何内容</p>
<p>在实际开发中，前后端都需要对表单的数据进行合法性的验证，而且，<strong>后端做为数据合法性验证的最后一个关口</strong>，在拦截非法数据方面，起到了至关重要的作用。</p>
<p>单纯的使用 <code>if...else...</code> 的形式对数据合法性进行验证，效率低下、出错率高、维护性差。因此，推荐使用<strong>第三方数据验证模块</strong>，来降低出错率、提高验证的效率与可维护性，<strong>让后端程序员把更多的精力放在核心业务逻辑的处理上</strong>。</p>
<ol>
<li><p>安装 <code>@hapi/joi</code> 包，为表单中携带的每个数据项，定义验证规则：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">npm install @hapi/joi@<span class="hljs-number">17.1</span><span class="hljs-number">.0</span><br></code></pre></td></tr></table></figure></li>
<li><p>安装 <code>@escook/express-joi</code> 中间件，来实现自动对表单数据进行验证的功能：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">npm i @escook/express-joi<br></code></pre></td></tr></table></figure></li>
<li><p>新建 <code>/schema/user.js</code> 用户信息验证规则模块，并初始化代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@hapi/joi&#x27;</span>)<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * string() 值必须是字符串</span><br><span class="hljs-comment"> * alphanum() 值只能是包含 a-zA-Z0-9 的字符串</span><br><span class="hljs-comment"> * min(length) 最小长度</span><br><span class="hljs-comment"> * max(length) 最大长度</span><br><span class="hljs-comment"> * required() 值是必填项，不能为 undefined</span><br><span class="hljs-comment"> * pattern(正则表达式) 值必须符合正则表达式的规则</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-comment">// 用户名的验证规则</span><br><span class="hljs-keyword">const</span> username = joi.<span class="hljs-title function_">string</span>().<span class="hljs-title function_">alphanum</span>().<span class="hljs-title function_">min</span>(<span class="hljs-number">1</span>).<span class="hljs-title function_">max</span>(<span class="hljs-number">10</span>).required()<br><span class="hljs-comment">// 密码的验证规则</span><br><span class="hljs-keyword">const</span> password = joi<br>  .<span class="hljs-title function_">string</span>()<br>  .<span class="hljs-title function_">pattern</span>(<span class="hljs-regexp">/^[\S]&#123;6,12&#125;$/</span>)<br>  .required()<br><br><span class="hljs-comment">// 注册和登录表单的验证规则对象</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">reg_login_schema</span> = &#123;<br>  <span class="hljs-comment">// 表示需要对 req.body 中的数据进行验证</span><br>  <span class="hljs-attr">body</span>: &#123;<br>    username,<br>    password,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>修改 <code>/router/user.js</code> 中的代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 导入用户路由处理函数模块</span><br><span class="hljs-keyword">const</span> userHandler = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../router_handler/user&#x27;</span>)<br><br><span class="hljs-comment">// 1. 导入验证表单数据的中间件</span><br><span class="hljs-keyword">const</span> expressJoi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@escook/express-joi&#x27;</span>)<br><span class="hljs-comment">// 2. 导入需要的验证规则对象</span><br><span class="hljs-keyword">const</span> &#123; reg_login_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/user&#x27;</span>)<br><br><span class="hljs-comment">// 注册新用户</span><br><span class="hljs-comment">// 3. 在注册新用户的路由中，声明局部中间件，对当前请求中携带的数据进行验证</span><br><span class="hljs-comment">// 3.1 数据验证通过后，会把这次请求流转给后面的路由处理函数</span><br><span class="hljs-comment">// 3.2 数据验证失败后，终止后续代码的执行，并抛出一个全局的 Error 错误，进入全局错误级别中间件中进行处理</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/reguser&#x27;</span>, <span class="hljs-title function_">expressJoi</span>(reg_login_schema), userHandler.<span class="hljs-property">regUser</span>)<br><span class="hljs-comment">// 登录</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/login&#x27;</span>, userHandler.<span class="hljs-property">login</span>)<br><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 的全局错误级别中间件中，捕获验证失败的错误，并把验证失败的结果响应给客户端：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@hapi/joi&#x27;</span>)<br><br><span class="hljs-comment">// 错误中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">err, req, res, next</span>) &#123;<br>  <span class="hljs-comment">// 数据验证失败</span><br>  <span class="hljs-keyword">if</span> (err <span class="hljs-keyword">instanceof</span> joi.<span class="hljs-property">ValidationError</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br>  <span class="hljs-comment">// 未知错误</span><br>  res.<span class="hljs-title function_">cc</span>(err)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="2-6-登录"><a href="#2-6-登录" class="headerlink" title="2.6 登录"></a>2.6 登录</h3><h4 id="2-6-0-实现步骤"><a href="#2-6-0-实现步骤" class="headerlink" title="2.6.0 实现步骤"></a>2.6.0 实现步骤</h4><ol>
<li>检测表单数据是否合法</li>
<li>根据用户名查询用户的数据</li>
<li>判断用户输入的密码是否正确</li>
<li>生成 JWT 的 Token 字符串</li>
</ol>
<h4 id="2-6-1-检测登录表单的数据是否合法"><a href="#2-6-1-检测登录表单的数据是否合法" class="headerlink" title="2.6.1 检测登录表单的数据是否合法"></a>2.6.1 检测登录表单的数据是否合法</h4><p>将 <code>/router/user.js</code> 中 登录 的路由代码修改如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 登录的路由</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/login&#x27;</span>, <span class="hljs-title function_">expressJoi</span>(reg_login_schema), userHandler.<span class="hljs-property">login</span>)<br></code></pre></td></tr></table></figure>

<h4 id="2-6-2-根据用户名查询用户的数据"><a href="#2-6-2-根据用户名查询用户的数据" class="headerlink" title="2.6.2 根据用户名查询用户的数据"></a>2.6.2 根据用户名查询用户的数据</h4><ol>
<li><p>接收表单数据：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> userinfo = req.<span class="hljs-property">body</span><br></code></pre></td></tr></table></figure></li>
<li><p>定义 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select * from ev_users where username=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>执行 SQL 语句，查询用户的数据：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, userinfo.<span class="hljs-property">username</span>, <span class="hljs-keyword">function</span> (<span class="hljs-params">err, results</span>) &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br>  <span class="hljs-comment">// 执行 SQL 语句成功，但是查询到数据条数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;登录失败！&#x27;</span>)<br>  <span class="hljs-comment">// TODO：判断用户输入的登录密码是否和数据库中的密码一致</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="2-6-3-判断用户输入的密码是否正确"><a href="#2-6-3-判断用户输入的密码是否正确" class="headerlink" title="2.6.3 判断用户输入的密码是否正确"></a>2.6.3 判断用户输入的密码是否正确</h4><p>核心实现思路：调用 <code>bcrypt.compareSync(用户提交的密码, 数据库中的密码)</code> 方法比较密码是否一致</p>
<p>返回值是布尔值</p>
<p>具体的实现代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 拿着用户输入的密码,和数据库中存储的密码进行对比</span><br><span class="hljs-keyword">const</span> compareResult = bcrypt.<span class="hljs-title function_">compareSync</span>(userinfo.<span class="hljs-property">password</span>, results[<span class="hljs-number">0</span>].<span class="hljs-property">password</span>)<br><br><span class="hljs-comment">// 如果对比的结果等于 false, 则证明用户输入的密码错误</span><br><span class="hljs-keyword">if</span> (!compareResult) &#123;<br>  <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;登录失败！&#x27;</span>)<br>&#125;<br><br><span class="hljs-comment">// TODO：登录成功，生成 Token 字符串</span><br></code></pre></td></tr></table></figure>

<h4 id="2-6-4-生成-JWT-的-Token-字符串"><a href="#2-6-4-生成-JWT-的-Token-字符串" class="headerlink" title="2.6.4 生成 JWT 的 Token 字符串"></a>2.6.4 生成 JWT 的 Token 字符串</h4><p>核心注意点：在生成 Token 字符串的时候，一定要剔除 <strong>密码</strong> 和 <strong>头像</strong> 的值</p>
<ol>
<li><p>通过 ES6 的高级语法，快速剔除 <code>密码</code> 和 <code>头像</code> 的值：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 剔除完毕之后，user 中只保留了用户的 id, username, nickname, email 这四个属性的值</span><br><span class="hljs-keyword">const</span> user = &#123; ...results[<span class="hljs-number">0</span>], <span class="hljs-attr">password</span>: <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-attr">user_pic</span>: <span class="hljs-string">&#x27;&#x27;</span> &#125;<br></code></pre></td></tr></table></figure></li>
<li><p>运行如下的命令，安装生成 Token 字符串的包：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">npm i jsonwebtoken@<span class="hljs-number">8.5</span><span class="hljs-number">.1</span><br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/user.js</code> 模块的头部区域，导入 <code>jsonwebtoken</code> 包：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 用这个包来生成 Token 字符串</span><br><span class="hljs-keyword">const</span> jwt = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;jsonwebtoken&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>创建 <code>config.js</code> 文件，并向外共享 <strong>加密</strong> 和 <strong>还原</strong> Token 的 <code>jwtSecretKey</code> 字符串：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = &#123;<br>  <span class="hljs-attr">jwtSecretKey</span>: <span class="hljs-string">&#x27;itheima No1. ^_^&#x27;</span>,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>将用户信息对象加密成 Token 字符串：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入配置文件</span><br><span class="hljs-keyword">const</span> config = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../config&#x27;</span>)<br><br><span class="hljs-comment">// 生成 Token 字符串</span><br><span class="hljs-keyword">const</span> tokenStr = jwt.<span class="hljs-title function_">sign</span>(user, config.<span class="hljs-property">jwtSecretKey</span>, &#123;<br>  <span class="hljs-attr">expiresIn</span>: <span class="hljs-string">&#x27;10h&#x27;</span>, <span class="hljs-comment">// token 有效期为 10 个小时</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
<li><p>将生成的 Token 字符串响应给客户端：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js">res.<span class="hljs-title function_">send</span>(&#123;<br>  <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,<br>  <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;登录成功！&#x27;</span>,<br>  <span class="hljs-comment">// 为了方便客户端使用 Token，在服务器端直接拼接上 Bearer 的前缀</span><br>  <span class="hljs-attr">token</span>: <span class="hljs-string">&#x27;Bearer &#x27;</span> + tokenStr,<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="2-7-配置解析-Token-的中间件"><a href="#2-7-配置解析-Token-的中间件" class="headerlink" title="2.7 配置解析 Token 的中间件"></a>2.7 配置解析 Token 的中间件</h3><ol>
<li><p>运行如下的命令，安装解析 Token 的中间件：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">npm i express-jwt@<span class="hljs-number">5.3</span><span class="hljs-number">.3</span><br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中注册路由之前，配置解析 Token 的中间件：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入配置文件</span><br><span class="hljs-keyword">const</span> config = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./config&#x27;</span>)<br><br><span class="hljs-comment">// 解析 token 的中间件</span><br><span class="hljs-keyword">const</span> expressJWT = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express-jwt&#x27;</span>)<br><br><span class="hljs-comment">// 使用 .unless(&#123; path: [/^\/api\//] &#125;) 指定哪些接口不需要进行 Token 的身份认证</span><br>app.<span class="hljs-title function_">use</span>(<br>  <span class="hljs-title function_">expressJWT</span>(&#123; <span class="hljs-attr">secret</span>: config.<span class="hljs-property">jwtSecretKey</span> &#125;).<span class="hljs-title function_">unless</span>(&#123; <span class="hljs-attr">path</span>: [<span class="hljs-regexp">/^\/api\//</span>] &#125;)<br>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中的 <code>错误级别中间件</code> 里面，捕获并处理 Token 认证失败后的错误：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 错误中间件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-keyword">function</span> (<span class="hljs-params">err, req, res, next</span>) &#123;<br>  <span class="hljs-comment">// 省略其它代码...</span><br><br>  <span class="hljs-comment">// 捕获身份认证失败的错误</span><br>  <span class="hljs-keyword">if</span> (err.<span class="hljs-property">name</span> === <span class="hljs-string">&#x27;UnauthorizedError&#x27;</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;身份认证失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 未知错误...</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h2 id="3-个人中心"><a href="#3-个人中心" class="headerlink" title="3. 个人中心"></a>3. 个人中心</h2><h3 id="3-1-获取用户的基本信息"><a href="#3-1-获取用户的基本信息" class="headerlink" title="3.1 获取用户的基本信息"></a>3.1 获取用户的基本信息</h3><h4 id="3-1-0-实现步骤"><a href="#3-1-0-实现步骤" class="headerlink" title="3.1.0 实现步骤"></a>3.1.0 实现步骤</h4><ol>
<li>初始化 <strong>路由</strong> 模块</li>
<li>初始化 <strong>路由处理函数</strong> 模块</li>
<li>获取用户的基本信息</li>
</ol>
<h4 id="3-1-1-初始化路由模块"><a href="#3-1-1-初始化路由模块" class="headerlink" title="3.1.1 初始化路由模块"></a>3.1.1 初始化路由模块</h4><ol>
<li><p>创建 <code>/router/userinfo.js</code> 路由模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入 express</span><br><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-comment">// 创建路由对象</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 获取用户的基本信息</span><br>router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/userinfo&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;)<br><br><span class="hljs-comment">// 向外共享路由对象</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中导入并使用个人中心的路由模块：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入并使用用户信息路由模块</span><br><span class="hljs-keyword">const</span> userinfoRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./router/userinfo&#x27;</span>)<br><span class="hljs-comment">// 注意：以 /my 开头的接口，都是有权限的接口，需要进行 Token 身份认证</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/my&#x27;</span>, userinfoRouter)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-1-2-初始化路由处理函数模块"><a href="#3-1-2-初始化路由处理函数模块" class="headerlink" title="3.1.2 初始化路由处理函数模块"></a>3.1.2 初始化路由处理函数模块</h4><ol>
<li><p>创建 <code>/router_handler/userinfo.js</code> 路由处理函数模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 获取用户基本信息的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">getUserInfo</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>修改 <code>/router/userinfo.js</code> 中的代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 导入用户信息的处理函数模块</span><br><span class="hljs-keyword">const</span> userinfo_handler = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../router_handler/userinfo&#x27;</span>)<br><br><span class="hljs-comment">// 获取用户的基本信息</span><br>router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/userinfo&#x27;</span>, userinfo_handler.<span class="hljs-property">getUserInfo</span>)<br><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-1-3-获取用户的基本信息"><a href="#3-1-3-获取用户的基本信息" class="headerlink" title="3.1.3 获取用户的基本信息"></a>3.1.3 获取用户的基本信息</h4><ol>
<li><p>在 <code>/router_handler/userinfo.js</code> 头部导入数据库操作模块：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入数据库操作模块</span><br><span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../db/index&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>定义 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 根据用户的 id，查询用户的基本信息</span><br><span class="hljs-comment">// 注意：为了防止用户的密码泄露，需要排除 password 字段</span><br><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select id, username, nickname, email, user_pic from ev_users where id=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 注意：req 对象上的 user 属性，是 Token 解析成功，express-jwt 中间件帮我们挂载上去的</span><br>db.<span class="hljs-title function_">query</span>(sql, req.<span class="hljs-property">user</span>.<span class="hljs-property">id</span>, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 1. 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 2. 执行 SQL 语句成功，但是查询到的数据条数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;获取用户信息失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 3. 将用户信息响应给客户端</span><br>  res.<span class="hljs-title function_">send</span>(&#123;<br>    <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,<br>    <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;获取用户基本信息成功！&#x27;</span>,<br>    <span class="hljs-attr">data</span>: results[<span class="hljs-number">0</span>],<br>  &#125;)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="3-2-更新用户的基本信息"><a href="#3-2-更新用户的基本信息" class="headerlink" title="3.2 更新用户的基本信息"></a>3.2 更新用户的基本信息</h3><h4 id="3-2-0-实现步骤"><a href="#3-2-0-实现步骤" class="headerlink" title="3.2.0 实现步骤"></a>3.2.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>实现更新用户基本信息的功能</li>
</ol>
<h4 id="3-2-1-定义路由和处理函数"><a href="#3-2-1-定义路由和处理函数" class="headerlink" title="3.2.1 定义路由和处理函数"></a>3.2.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/userinfo.js</code> 模块中，新增 <code>更新用户基本信息</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新用户的基本信息</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/userinfo&#x27;</span>, userinfo_handler.<span class="hljs-property">updateUserInfo</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/userinfo.js</code> 模块中，定义并向外共享 <code>更新用户基本信息</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新用户基本信息的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">updateUserInfo</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-2-2-验证表单数据"><a href="#3-2-2-验证表单数据" class="headerlink" title="3.2.2 验证表单数据"></a>3.2.2 验证表单数据</h4><ol>
<li><p>在 <code>/schema/user.js</code> 验证规则模块中，定义 <code>id</code>，<code>nickname</code>，<code>email</code> 的验证规则如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 定义 id, nickname, emial 的验证规则</span><br><span class="hljs-keyword">const</span> id = joi.<span class="hljs-title function_">number</span>().<span class="hljs-title function_">integer</span>().<span class="hljs-title function_">min</span>(<span class="hljs-number">1</span>).required()<br><span class="hljs-keyword">const</span> nickname = joi.<span class="hljs-title function_">string</span>().required()<br><span class="hljs-keyword">const</span> email = joi.<span class="hljs-title function_">string</span>().<span class="hljs-title function_">email</span>().required()<br></code></pre></td></tr></table></figure></li>
<li><p>并使用 <code>exports</code> 向外共享如下的 <code>验证规则对象</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 验证规则对象 - 更新用户基本信息</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">update_userinfo_schema</span> = &#123;<br>  <span class="hljs-attr">body</span>: &#123;<br>    id,<br>    nickname,<br>    email,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/userinfo.js</code> 模块中，导入验证数据合法性的中间件：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入验证数据合法性的中间件</span><br><span class="hljs-keyword">const</span> expressJoi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@escook/express-joi&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/userinfo.js</code> 模块中，导入需要的验证规则对象：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入需要的验证规则对象</span><br><span class="hljs-keyword">const</span> &#123; update_userinfo_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/user&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/userinfo.js</code> 模块中，修改 <code>更新用户的基本信息</code> 的路由如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新用户的基本信息</span><br>router.<span class="hljs-title function_">post</span>(<br>  <span class="hljs-string">&#x27;/userinfo&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(update_userinfo_schema),<br>  userinfo_handler.<span class="hljs-property">updateUserInfo</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-2-3-实现更新用户基本信息的功能"><a href="#3-2-3-实现更新用户基本信息的功能" class="headerlink" title="3.2.3 实现更新用户基本信息的功能"></a>3.2.3 实现更新用户基本信息的功能</h4><ol>
<li><p>定义待执行的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`update ev_users set ? where id=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句并传参：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, [req.<span class="hljs-property">body</span>, req.<span class="hljs-property">body</span>.<span class="hljs-property">id</span>], <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 执行 SQL 语句成功，但影响行数不为 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;修改用户基本信息失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 修改用户信息成功</span><br>  <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;修改用户基本信息成功！&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="3-3-重置密码"><a href="#3-3-重置密码" class="headerlink" title="3.3 重置密码"></a>3.3 重置密码</h3><h4 id="3-3-0-实现步骤"><a href="#3-3-0-实现步骤" class="headerlink" title="3.3.0 实现步骤"></a>3.3.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>实现重置密码的功能</li>
</ol>
<h4 id="3-3-1-定义路由和处理函数"><a href="#3-3-1-定义路由和处理函数" class="headerlink" title="3.3.1 定义路由和处理函数"></a>3.3.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/userinfo.js</code> 模块中，新增 <code>重置密码</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 重置密码的路由</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/updatepwd&#x27;</span>, userinfo_handler.<span class="hljs-property">updatePassword</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/userinfo.js</code> 模块中，定义并向外共享 <code>重置密码</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 重置密码的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">updatePassword</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-3-2-验证表单数据"><a href="#3-3-2-验证表单数据" class="headerlink" title="3.3.2 验证表单数据"></a>3.3.2 验证表单数据</h4><p><code>核心验证思路：旧密码与新密码，必须符合密码的验证规则，并且新密码不能与旧密码一致！</code></p>
<ol>
<li><p>在 <code>/schema/user.js</code> 模块中，使用 <code>exports</code> 向外共享如下的 <code>验证规则对象</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 验证规则对象 - 重置密码</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">update_password_schema</span> = &#123;<br>  <span class="hljs-attr">body</span>: &#123;<br>    <span class="hljs-comment">// 使用 password 这个规则，验证 req.body.oldPwd 的值</span><br>    <span class="hljs-attr">oldPwd</span>: password,<br>    <span class="hljs-comment">// 使用 joi.not(joi.ref(&#x27;oldPwd&#x27;)).concat(password) 规则，验证 req.body.newPwd 的值</span><br>    <span class="hljs-comment">// 解读：</span><br>    <span class="hljs-comment">// 1. joi.ref(&#x27;oldPwd&#x27;) 表示 newPwd 的值必须和 oldPwd 的值保持一致</span><br>    <span class="hljs-comment">// 2. joi.not(joi.ref(&#x27;oldPwd&#x27;)) 表示 newPwd 的值不能等于 oldPwd 的值</span><br>    <span class="hljs-comment">// 3. .concat() 用于合并 joi.not(joi.ref(&#x27;oldPwd&#x27;)) 和 password 这两条验证规则</span><br>    <span class="hljs-attr">newPwd</span>: joi.<span class="hljs-title function_">not</span>(joi.<span class="hljs-title function_">ref</span>(<span class="hljs-string">&#x27;oldPwd&#x27;</span>)).<span class="hljs-title function_">concat</span>(password),<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/userinfo.js</code> 模块中，导入需要的验证规则对象：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入需要的验证规则对象</span><br><span class="hljs-keyword">const</span> &#123;<br>  update_userinfo_schema,<br>  update_password_schema,<br>&#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/user&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>并在 <code>重置密码的路由</code> 中，使用 <code>update_password_schema</code> 规则验证表单的数据，示例代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js">router.<span class="hljs-title function_">post</span>(<br>  <span class="hljs-string">&#x27;/updatepwd&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(update_password_schema),<br>  userinfo_handler.<span class="hljs-property">updatePassword</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-3-3-实现重置密码的功能"><a href="#3-3-3-实现重置密码的功能" class="headerlink" title="3.3.3 实现重置密码的功能"></a>3.3.3 实现重置密码的功能</h4><ol>
<li><p>根据 <code>id</code> 查询用户是否存在：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 定义根据 id 查询用户数据的 SQL 语句</span><br><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select * from ev_users where id=?`</span><br><br><span class="hljs-comment">// 执行 SQL 语句查询用户是否存在</span><br>db.<span class="hljs-title function_">query</span>(sql, req.<span class="hljs-property">user</span>.<span class="hljs-property">id</span>, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 检查指定 id 的用户是否存在</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;用户不存在！&#x27;</span>)<br><br>  <span class="hljs-comment">// TODO：判断提交的旧密码是否正确</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
<li><p>判断提交的 <strong>旧密码</strong> 是否正确：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 在头部区域导入 bcryptjs 后，</span><br><span class="hljs-comment">// 即可使用 bcrypt.compareSync(提交的密码，数据库中的密码) 方法验证密码是否正确</span><br><span class="hljs-comment">// compareSync() 函数的返回值为布尔值，true 表示密码正确，false 表示密码错误</span><br><span class="hljs-keyword">const</span> bcrypt = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;bcryptjs&#x27;</span>)<br><br><span class="hljs-comment">// 判断提交的旧密码是否正确</span><br><span class="hljs-keyword">const</span> compareResult = bcrypt.<span class="hljs-title function_">compareSync</span>(<br>  req.<span class="hljs-property">body</span>.<span class="hljs-property">oldPwd</span>,<br>  results[<span class="hljs-number">0</span>].<span class="hljs-property">password</span><br>)<br><span class="hljs-keyword">if</span> (!compareResult) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;原密码错误！&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>对新密码进行 <code>bcrypt</code> 加密之后，更新到数据库中：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 定义更新用户密码的 SQL 语句</span><br><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`update ev_users set password=? where id=?`</span><br><br><span class="hljs-comment">// 对新密码进行 bcrypt 加密处理</span><br><span class="hljs-keyword">const</span> newPwd = bcrypt.<span class="hljs-title function_">hashSync</span>(req.<span class="hljs-property">body</span>.<span class="hljs-property">newPwd</span>, <span class="hljs-number">10</span>)<br><br><span class="hljs-comment">// 执行 SQL 语句，根据 id 更新用户的密码</span><br>db.<span class="hljs-title function_">query</span>(sql, [newPwd, req.<span class="hljs-property">user</span>.<span class="hljs-property">id</span>], <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// SQL 语句执行失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// SQL 语句执行成功，但是影响行数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;更新密码失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 更新密码成功</span><br>  res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;更新密码成功！&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="3-4-更新用户头像"><a href="#3-4-更新用户头像" class="headerlink" title="3.4 更新用户头像"></a>3.4 更新用户头像</h3><h4 id="3-4-0-实现步骤"><a href="#3-4-0-实现步骤" class="headerlink" title="3.4.0 实现步骤"></a>3.4.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>实现更新用户头像的功能</li>
</ol>
<h4 id="3-4-1-定义路由和处理函数"><a href="#3-4-1-定义路由和处理函数" class="headerlink" title="3.4.1 定义路由和处理函数"></a>3.4.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/userinfo.js</code> 模块中，新增 <code>更新用户头像</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新用户头像的路由</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/update/avatar&#x27;</span>, userinfo_handler.<span class="hljs-property">updateAvatar</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/userinfo.js</code> 模块中，定义并向外共享 <code>更新用户头像</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新用户头像的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">updateAvatar</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-4-2-验证表单数据"><a href="#3-4-2-验证表单数据" class="headerlink" title="3.4.2 验证表单数据"></a>3.4.2 验证表单数据</h4><ol>
<li><p>在 <code>/schema/user.js</code> 验证规则模块中，定义 <code>avatar</code> 的验证规则如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// dataUri() 指的是如下格式的字符串数据：</span><br><span class="hljs-comment">// </span><br><span class="hljs-keyword">const</span> avatar = joi.<span class="hljs-title function_">string</span>().<span class="hljs-title function_">dataUri</span>().required()<br></code></pre></td></tr></table></figure></li>
<li><p>并使用 <code>exports</code> 向外共享如下的 <code>验证规则对象</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 验证规则对象 - 更新头像</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">update_avatar_schema</span> = &#123;<br>  <span class="hljs-attr">body</span>: &#123;<br>    avatar,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/userinfo.js</code> 模块中，导入需要的验证规则对象：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> &#123; update_avatar_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/user&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/userinfo.js</code> 模块中，修改 <code>更新用户头像</code> 的路由如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js">router.<span class="hljs-title function_">post</span>(<br>  <span class="hljs-string">&#x27;/update/avatar&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(update_avatar_schema),<br>  userinfo_handler.<span class="hljs-property">updateAvatar</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="3-4-3-实现更新用户头像的功能"><a href="#3-4-3-实现更新用户头像的功能" class="headerlink" title="3.4.3 实现更新用户头像的功能"></a>3.4.3 实现更新用户头像的功能</h4><ol>
<li><p>定义更新用户头像的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">&#x27;update ev_users set user_pic=? where id=?&#x27;</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句，更新对应用户的头像：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, [req.<span class="hljs-property">body</span>.<span class="hljs-property">avatar</span>, req.<span class="hljs-property">user</span>.<span class="hljs-property">id</span>], <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 执行 SQL 语句成功，但是影响行数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;更新头像失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 更新用户头像成功</span><br>  <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;更新头像成功！&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h2 id="4-文章分类管理"><a href="#4-文章分类管理" class="headerlink" title="4.文章分类管理"></a>4.文章分类管理</h2><h3 id="4-1-新建-ev-article-cate-表"><a href="#4-1-新建-ev-article-cate-表" class="headerlink" title="4.1 新建 ev_article_cate 表"></a>4.1 新建 ev_article_cate 表</h3><h4 id="4-1-1-创建表结构"><a href="#4-1-1-创建表结构" class="headerlink" title="4.1.1 创建表结构"></a>4.1.1 创建表结构</h4><p><img src="https://pic.imgdb.cn/item/63883c2116f2c2beb1ce5f35.jpg" srcset="/img/loading.gif" lazyload></p>
<h4 id="4-1-2-新增两条初始数据"><a href="#4-1-2-新增两条初始数据" class="headerlink" title="4.1.2 新增两条初始数据"></a>4.1.2 新增两条初始数据</h4><p><img src="https://pic.imgdb.cn/item/63883c4216f2c2beb1ce8193.jpg" srcset="/img/loading.gif" lazyload></p>
<h3 id="4-2-获取文章分类列表"><a href="#4-2-获取文章分类列表" class="headerlink" title="4.2 获取文章分类列表"></a>4.2 获取文章分类列表</h3><h4 id="4-2-0-实现步骤"><a href="#4-2-0-实现步骤" class="headerlink" title="4.2.0 实现步骤"></a>4.2.0 实现步骤</h4><ol>
<li>初始化路由模块</li>
<li>初始化路由处理函数模块</li>
<li>获取文章分类列表数据</li>
</ol>
<h4 id="4-2-1-初始化路由模块"><a href="#4-2-1-初始化路由模块" class="headerlink" title="4.2.1 初始化路由模块"></a>4.2.1 初始化路由模块</h4><ol>
<li><p>创建 <code>/router/artcate.js</code> 路由模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入 express</span><br><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-comment">// 创建路由对象</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 获取文章分类的列表数据</span><br>router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/cates&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;)<br><br><span class="hljs-comment">// 向外共享路由对象</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中导入并使用文章分类的路由模块：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入并使用文章分类路由模块</span><br><span class="hljs-keyword">const</span> artCateRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./router/artcate&#x27;</span>)<br><span class="hljs-comment">// 为文章分类的路由挂载统一的访问前缀 /my/article</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/my/article&#x27;</span>, artCateRouter)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-2-2-初始化路由处理函数模块"><a href="#4-2-2-初始化路由处理函数模块" class="headerlink" title="4.2.2 初始化路由处理函数模块"></a>4.2.2 初始化路由处理函数模块</h4><ol>
<li><p>创建 <code>/router_handler/artcate.js</code> 路由处理函数模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 获取文章分类列表数据的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">getArticleCates</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>修改 <code>/router/artcate.js</code> 中的代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 导入文章分类的路由处理函数模块</span><br><span class="hljs-keyword">const</span> artcate_handler = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../router_handler/artcate&#x27;</span>)<br><br><span class="hljs-comment">// 获取文章分类的列表数据</span><br>router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/cates&#x27;</span>, artcate_handler.<span class="hljs-property">getArticleCates</span>)<br><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-2-3-获取文章分类列表数据"><a href="#4-2-3-获取文章分类列表数据" class="headerlink" title="4.2.3 获取文章分类列表数据"></a>4.2.3 获取文章分类列表数据</h4><ol>
<li><p>在 <code>/router_handler/artcate.js</code> 头部导入数据库操作模块：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入数据库操作模块</span><br><span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../db/index&#x27;</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>定义 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 根据分类的状态，获取所有未被删除的分类列表数据</span><br><span class="hljs-comment">// is_delete 为 0 表示没有被 标记为删除 的数据</span><br><span class="hljs-keyword">const</span> sql = <span class="hljs-string">&#x27;select * from ev_article_cate where is_delete=0 order by id asc&#x27;</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 1. 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 2. 执行 SQL 语句成功</span><br>  res.<span class="hljs-title function_">send</span>(&#123;<br>    <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,<br>    <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;获取文章分类列表成功！&#x27;</span>,<br>    <span class="hljs-attr">data</span>: results,<br>  &#125;)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="4-3-新增文章分类"><a href="#4-3-新增文章分类" class="headerlink" title="4.3 新增文章分类"></a>4.3 新增文章分类</h3><h4 id="4-3-0-实现步骤"><a href="#4-3-0-实现步骤" class="headerlink" title="4.3.0 实现步骤"></a>4.3.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>查询 <code>分类名称</code> 与 <code>分类别名</code> 是否被占用</li>
<li>实现新增文章分类的功能</li>
</ol>
<h4 id="4-3-1-定义路由和处理函数"><a href="#4-3-1-定义路由和处理函数" class="headerlink" title="4.3.1 定义路由和处理函数"></a>4.3.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/artcate.js</code> 模块中，添加 <code>新增文章分类</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 新增文章分类的路由</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/addcates&#x27;</span>, artcate_handler.<span class="hljs-property">addArticleCates</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/artcate.js</code> 模块中，定义并向外共享 <code>新增文章分类</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 新增文章分类的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">addArticleCates</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-3-2-验证表单数据"><a href="#4-3-2-验证表单数据" class="headerlink" title="4.3.2 验证表单数据"></a>4.3.2 验证表单数据</h4><ol>
<li><p>创建 <code>/schema/artcate.js</code> 文章分类数据验证模块，并定义如下的验证规则：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入定义验证规则的模块</span><br><span class="hljs-keyword">const</span> joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@hapi/joi&#x27;</span>)<br><br><span class="hljs-comment">// 定义 分类名称 和 分类别名 的校验规则</span><br><span class="hljs-keyword">const</span> name = joi.<span class="hljs-title function_">string</span>().required()<br><span class="hljs-keyword">const</span> alias = joi.<span class="hljs-title function_">string</span>().<span class="hljs-title function_">alphanum</span>().required()<br><br><span class="hljs-comment">// 校验规则对象 - 添加分类</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">add_cate_schema</span> = &#123;<br>  <span class="hljs-attr">body</span>: &#123;<br>    name,<br>    alias,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/artcate.js</code> 模块中，使用 <code>add_cate_schema</code> 对数据进行验证：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入验证数据的中间件</span><br><span class="hljs-keyword">const</span> expressJoi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@escook/express-joi&#x27;</span>)<br><span class="hljs-comment">// 导入文章分类的验证模块</span><br><span class="hljs-keyword">const</span> &#123; add_cate_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/artcate&#x27;</span>)<br><br><span class="hljs-comment">// 新增文章分类的路由</span><br>router.<span class="hljs-title function_">post</span>(<br>  <span class="hljs-string">&#x27;/addcates&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(add_cate_schema),<br>  artcate_handler.<span class="hljs-property">addArticleCates</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-3-3-查询分类名称与别名是否被占用"><a href="#4-3-3-查询分类名称与别名是否被占用" class="headerlink" title="4.3.3 查询分类名称与别名是否被占用"></a>4.3.3 查询分类名称与别名是否被占用</h4><ol>
<li><p>定义查重的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 定义查询 分类名称 与 分类别名 是否被占用的 SQL 语句</span><br><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select * from ev_article_cate where name=? or alias=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行查重的操作：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 执行查重操作</span><br>db.<span class="hljs-title function_">query</span>(sql, [req.<span class="hljs-property">body</span>.<span class="hljs-property">name</span>, req.<span class="hljs-property">body</span>.<span class="hljs-property">alias</span>], <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 分类名称 和 分类别名 都被占用</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> === <span class="hljs-number">2</span>)<br>    <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类名称与别名被占用，请更换后重试！&#x27;</span>)<br>  <span class="hljs-keyword">if</span> (<br>    results.<span class="hljs-property">length</span> === <span class="hljs-number">1</span> &amp;&amp;<br>    results[<span class="hljs-number">0</span>].<span class="hljs-property">name</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">name</span> &amp;&amp;<br>    results[<span class="hljs-number">0</span>].<span class="hljs-property">alias</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">alias</span><br>  )<br>    <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类名称与别名被占用，请更换后重试！&#x27;</span>)<br>  <span class="hljs-comment">// 分类名称 或 分类别名 被占用</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> === <span class="hljs-number">1</span> &amp;&amp; results[<span class="hljs-number">0</span>].<span class="hljs-property">name</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">name</span>)<br>    <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类名称被占用，请更换后重试！&#x27;</span>)<br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> === <span class="hljs-number">1</span> &amp;&amp; results[<span class="hljs-number">0</span>].<span class="hljs-property">alias</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">alias</span>)<br>    <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类别名被占用，请更换后重试！&#x27;</span>)<br><br>  <span class="hljs-comment">// TODO：新增文章分类</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-3-4-实现新增文章分类的功能"><a href="#4-3-4-实现新增文章分类的功能" class="headerlink" title="4.3.4 实现新增文章分类的功能"></a>4.3.4 实现新增文章分类的功能</h4><ol>
<li><p>定义新增文章分类的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`insert into ev_article_cate set ?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行新增文章分类的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, req.<span class="hljs-property">body</span>, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// SQL 语句执行失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// SQL 语句执行成功，但是影响行数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;新增文章分类失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 新增文章分类成功</span><br>  res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;新增文章分类成功！&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="4-4-根据-Id-删除文章分类"><a href="#4-4-根据-Id-删除文章分类" class="headerlink" title="4.4 根据 Id 删除文章分类"></a>4.4 根据 Id 删除文章分类</h3><h4 id="4-4-0-实现步骤"><a href="#4-4-0-实现步骤" class="headerlink" title="4.4.0 实现步骤"></a>4.4.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>实现删除文章分类的功能</li>
</ol>
<h4 id="4-4-1-定义路由和处理函数"><a href="#4-4-1-定义路由和处理函数" class="headerlink" title="4.4.1 定义路由和处理函数"></a>4.4.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/artcate.js</code> 模块中，添加 <code>删除文章分类</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 删除文章分类的路由</span><br>router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/deletecate/:id&#x27;</span>, artcate_handler.<span class="hljs-property">deleteCateById</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/artcate.js</code> 模块中，定义并向外共享 <code>删除文章分类</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 删除文章分类的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">deleteCateById</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-4-2-验证表单数据"><a href="#4-4-2-验证表单数据" class="headerlink" title="4.4.2 验证表单数据"></a>4.4.2 验证表单数据</h4><ol>
<li><p>在 <code>/schema/artcate.js</code> 验证规则模块中，定义 id 的验证规则如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 定义 分类Id 的校验规则</span><br><span class="hljs-keyword">const</span> id = joi.<span class="hljs-title function_">number</span>().<span class="hljs-title function_">integer</span>().<span class="hljs-title function_">min</span>(<span class="hljs-number">1</span>).required()<br></code></pre></td></tr></table></figure></li>
<li><p>并使用 <code>exports</code> 向外共享如下的 <code>验证规则对象</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 校验规则对象 - 删除分类</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">delete_cate_schema</span> = &#123;<br>  <span class="hljs-attr">params</span>: &#123;<br>    id,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/artcate.js</code> 模块中，导入需要的验证规则对象，并在路由中使用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入删除分类的验证规则对象</span><br><span class="hljs-keyword">const</span> &#123; delete_cate_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/artcate&#x27;</span>)<br><br><span class="hljs-comment">// 删除文章分类的路由</span><br>router.<span class="hljs-title function_">get</span>(<br>  <span class="hljs-string">&#x27;/deletecate/:id&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(delete_cate_schema),<br>  artcate_handler.<span class="hljs-property">deleteCateById</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-4-3-实现删除文章分类的功能"><a href="#4-4-3-实现删除文章分类的功能" class="headerlink" title="4.4.3 实现删除文章分类的功能"></a>4.4.3 实现删除文章分类的功能</h4><ol>
<li><p>定义删除文章分类的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`update ev_article_cate set is_delete=1 where id=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行删除文章分类的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, req.<span class="hljs-property">params</span>.<span class="hljs-property">id</span>, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// SQL 语句执行成功，但是影响行数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;删除文章分类失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 删除文章分类成功</span><br>  res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;删除文章分类成功！&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="4-5-根据-Id-获取文章分类数据"><a href="#4-5-根据-Id-获取文章分类数据" class="headerlink" title="4.5 根据 Id 获取文章分类数据"></a>4.5 根据 Id 获取文章分类数据</h3><h4 id="4-5-0-实现步骤"><a href="#4-5-0-实现步骤" class="headerlink" title="4.5.0 实现步骤"></a>4.5.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>实现获取文章分类的功能</li>
</ol>
<h4 id="4-5-1-定义路由和处理函数"><a href="#4-5-1-定义路由和处理函数" class="headerlink" title="4.5.1 定义路由和处理函数"></a>4.5.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/artcate.js</code> 模块中，添加 <code>根据 Id 获取文章分类</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">router.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/cates/:id&#x27;</span>, artcate_handler.<span class="hljs-property">getArtCateById</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/artcate.js</code> 模块中，定义并向外共享 <code>根据 Id 获取文章分类</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 根据 Id 获取文章分类的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">getArtCateById</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-5-2-验证表单数据"><a href="#4-5-2-验证表单数据" class="headerlink" title="4.5.2 验证表单数据"></a>4.5.2 验证表单数据</h4><ol>
<li><p>在 <code>/schema/artcate.js</code> 验证规则模块中，使用 <code>exports</code> 向外共享如下的 <code>验证规则对象</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 校验规则对象 - 根据 Id 获取分类</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">get_cate_schema</span> = &#123;<br>  <span class="hljs-attr">params</span>: &#123;<br>    id,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/artcate.js</code> 模块中，导入需要的验证规则对象，并在路由中使用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入根据 Id 获取分类的验证规则对象</span><br><span class="hljs-keyword">const</span> &#123; get_cate_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/artcate&#x27;</span>)<br><br><span class="hljs-comment">// 根据 Id 获取文章分类的路由</span><br>router.<span class="hljs-title function_">get</span>(<br>  <span class="hljs-string">&#x27;/cates/:id&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(get_cate_schema),<br>  artcate_handler.<span class="hljs-property">getArticleById</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-5-3-实现获取文章分类的功能"><a href="#4-5-3-实现获取文章分类的功能" class="headerlink" title="4.5.3 实现获取文章分类的功能"></a>4.5.3 实现获取文章分类的功能</h4><ol>
<li><p>定义根据 Id 获取文章分类的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select * from ev_article_cate where id=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, req.<span class="hljs-property">params</span>.<span class="hljs-property">id</span>, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// SQL 语句执行成功，但是没有查询到任何数据</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;获取文章分类数据失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 把数据响应给客户端</span><br>  res.<span class="hljs-title function_">send</span>(&#123;<br>    <span class="hljs-attr">status</span>: <span class="hljs-number">0</span>,<br>    <span class="hljs-attr">message</span>: <span class="hljs-string">&#x27;获取文章分类数据成功！&#x27;</span>,<br>    <span class="hljs-attr">data</span>: results[<span class="hljs-number">0</span>],<br>  &#125;)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h3 id="4-6-根据-Id-更新文章分类数据"><a href="#4-6-根据-Id-更新文章分类数据" class="headerlink" title="4.6 根据 Id 更新文章分类数据"></a>4.6 根据 Id 更新文章分类数据</h3><h4 id="4-6-0-实现步骤"><a href="#4-6-0-实现步骤" class="headerlink" title="4.6.0 实现步骤"></a>4.6.0 实现步骤</h4><ol>
<li>定义路由和处理函数</li>
<li>验证表单数据</li>
<li>查询 <code>分类名称</code> 与 <code>分类别名</code> 是否被占用</li>
<li>实现更新文章分类的功能</li>
</ol>
<h4 id="4-6-1-定义路由和处理函数"><a href="#4-6-1-定义路由和处理函数" class="headerlink" title="4.6.1 定义路由和处理函数"></a>4.6.1 定义路由和处理函数</h4><ol>
<li><p>在 <code>/router/artcate.js</code> 模块中，添加 <code>更新文章分类</code> 的路由：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新文章分类的路由</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/updatecate&#x27;</span>, artcate_handler.<span class="hljs-property">updateCateById</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/artcate.js</code> 模块中，定义并向外共享 <code>更新文章分类</code> 的路由处理函数：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 更新文章分类的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">updateCateById</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-6-2-验证表单数据"><a href="#4-6-2-验证表单数据" class="headerlink" title="4.6.2 验证表单数据"></a>4.6.2 验证表单数据</h4><ol>
<li><p>在 <code>/schema/artcate.js</code> 验证规则模块中，使用 <code>exports</code> 向外共享如下的 <code>验证规则对象</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 校验规则对象 - 更新分类</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">update_cate_schema</span> = &#123;<br>  <span class="hljs-attr">body</span>: &#123;<br>    <span class="hljs-title class_">Id</span>: id,<br>    name,<br>    alias,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/artcate.js</code> 模块中，导入需要的验证规则对象，并在路由中使用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入更新文章分类的验证规则对象</span><br><span class="hljs-keyword">const</span> &#123; update_cate_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/artcate&#x27;</span>)<br><br><span class="hljs-comment">// 更新文章分类的路由</span><br>router.<span class="hljs-title function_">post</span>(<br>  <span class="hljs-string">&#x27;/updatecate&#x27;</span>,<br>  <span class="hljs-title function_">expressJoi</span>(update_cate_schema),<br>  artcate_handler.<span class="hljs-property">updateCateById</span><br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-5-4-查询分类名称与别名是否被占用"><a href="#4-5-4-查询分类名称与别名是否被占用" class="headerlink" title="4.5.4 查询分类名称与别名是否被占用"></a>4.5.4 查询分类名称与别名是否被占用</h4><ol>
<li><p>定义查重的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 定义查询 分类名称 与 分类别名 是否被占用的 SQL 语句</span><br><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`select * from ev_article_cate where Id&lt;&gt;? and (name=? or alias=?)`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行查重的操作：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 执行查重操作</span><br>db.<span class="hljs-title function_">query</span>(<br>  sql,<br>  [req.<span class="hljs-property">body</span>.<span class="hljs-property">Id</span>, req.<span class="hljs-property">body</span>.<span class="hljs-property">name</span>, req.<span class="hljs-property">body</span>.<span class="hljs-property">alias</span>],<br>  <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 执行 SQL 语句失败</span><br>    <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>    <span class="hljs-comment">// 分类名称 和 分类别名 都被占用</span><br>    <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> === <span class="hljs-number">2</span>)<br>      <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类名称与别名被占用，请更换后重试！&#x27;</span>)<br>    <span class="hljs-keyword">if</span> (<br>      results.<span class="hljs-property">length</span> === <span class="hljs-number">1</span> &amp;&amp;<br>      results[<span class="hljs-number">0</span>].<span class="hljs-property">name</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">name</span> &amp;&amp;<br>      results[<span class="hljs-number">0</span>].<span class="hljs-property">alias</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">alias</span><br>    )<br>      <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类名称与别名被占用，请更换后重试！&#x27;</span>)<br>    <span class="hljs-comment">// 分类名称 或 分类别名 被占用</span><br>    <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> === <span class="hljs-number">1</span> &amp;&amp; results[<span class="hljs-number">0</span>].<span class="hljs-property">name</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">name</span>)<br>      <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类名称被占用，请更换后重试！&#x27;</span>)<br>    <span class="hljs-keyword">if</span> (results.<span class="hljs-property">length</span> === <span class="hljs-number">1</span> &amp;&amp; results[<span class="hljs-number">0</span>].<span class="hljs-property">alias</span> === req.<span class="hljs-property">body</span>.<span class="hljs-property">alias</span>)<br>      <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;分类别名被占用，请更换后重试！&#x27;</span>)<br><br>    <span class="hljs-comment">// TODO：更新文章分类</span><br>  &#125;<br>)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="4-5-5-实现更新文章分类的功能"><a href="#4-5-5-实现更新文章分类的功能" class="headerlink" title="4.5.5 实现更新文章分类的功能"></a>4.5.5 实现更新文章分类的功能</h4><ol>
<li><p>定义更新文章分类的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`update ev_article_cate set ? where Id=?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js">db.<span class="hljs-title function_">query</span>(sql, [req.<span class="hljs-property">body</span>, req.<span class="hljs-property">body</span>.<span class="hljs-property">Id</span>], <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// SQL 语句执行成功，但是影响行数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;更新文章分类失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 更新文章分类成功</span><br>  res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;更新文章分类成功！&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h2 id="5-文章管理"><a href="#5-文章管理" class="headerlink" title="5. 文章管理"></a>5. 文章管理</h2><h3 id="5-1-新建-ev-articles-表"><a href="#5-1-新建-ev-articles-表" class="headerlink" title="5.1 新建 ev_articles 表"></a>5.1 新建 ev_articles 表</h3><p><img src="https://pic.imgdb.cn/item/6388386716f2c2beb1c9ad03.jpg" srcset="/img/loading.gif" lazyload></p>
<h3 id="5-2-发布新文章"><a href="#5-2-发布新文章" class="headerlink" title="5.2 发布新文章"></a>5.2 发布新文章</h3><h4 id="5-2-0-实现步骤"><a href="#5-2-0-实现步骤" class="headerlink" title="5.2.0 实现步骤"></a>5.2.0 实现步骤</h4><ol>
<li>初始化路由模块</li>
<li>初始化路由处理函数模块</li>
<li>使用 multer 解析表单数据</li>
<li>验证表单数据</li>
<li>实现发布文章的功能</li>
</ol>
<h4 id="5-2-1-初始化路由模块"><a href="#5-2-1-初始化路由模块" class="headerlink" title="5.2.1 初始化路由模块"></a>5.2.1 初始化路由模块</h4><ol>
<li><p>创建 <code>/router/article.js</code> 路由模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入 express</span><br><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-comment">// 创建路由对象</span><br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 发布新文章</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/add&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;)<br><br><span class="hljs-comment">// 向外共享路由对象</span><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中导入并使用文章的路由模块：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入并使用文章路由模块</span><br><span class="hljs-keyword">const</span> articleRouter = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;./router/article&#x27;</span>)<br><span class="hljs-comment">// 为文章的路由挂载统一的访问前缀 /my/article</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/my/article&#x27;</span>, articleRouter)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="5-2-2-初始化路由处理函数模块"><a href="#5-2-2-初始化路由处理函数模块" class="headerlink" title="5.2.2 初始化路由处理函数模块"></a>5.2.2 初始化路由处理函数模块</h4><ol>
<li><p>创建 <code>/router_handler/article.js</code> 路由处理函数模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 发布新文章的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">addArticle</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>修改 <code>/router/article.js</code> 中的代码如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;express&#x27;</span>)<br><span class="hljs-keyword">const</span> router = express.<span class="hljs-title class_">Router</span>()<br><br><span class="hljs-comment">// 导入文章的路由处理函数模块</span><br><span class="hljs-keyword">const</span> article_handler = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../router_handler/article&#x27;</span>)<br><br><span class="hljs-comment">// 发布新文章</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/add&#x27;</span>, article_handler.<span class="hljs-property">addArticle</span>)<br><br><span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = router<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="5-2-3-使用-multer-解析表单数据"><a href="#5-2-3-使用-multer-解析表单数据" class="headerlink" title="5.2.3 使用 multer 解析表单数据"></a>5.2.3 使用 multer 解析表单数据</h4><p><code>注意：使用 express.urlencoded() 中间件无法解析 multipart/form-data 格式的请求体数据。</code></p>
<p><code>当前项目，推荐使用 multer 来解析 multipart/form-data 格式的表单数据。</code></p>
<ol>
<li><p>运行如下的终端命令，在项目中安装 <code>multer</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js">npm i multer@<span class="hljs-number">1.4</span><span class="hljs-number">.2</span><br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/article.js</code> 模块中导入并配置 <code>multer</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入解析 formdata 格式表单数据的包</span><br><span class="hljs-keyword">const</span> multer = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;multer&#x27;</span>)<br><span class="hljs-comment">// 导入处理路径的核心模块</span><br><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;path&#x27;</span>)<br><br><span class="hljs-comment">// 创建 multer 的实例对象，通过 dest 属性指定文件的存放路径</span><br><span class="hljs-keyword">const</span> upload = <span class="hljs-title function_">multer</span>(&#123; <span class="hljs-attr">dest</span>: path.<span class="hljs-title function_">join</span>(__dirname, <span class="hljs-string">&#x27;../uploads&#x27;</span>) &#125;)<br></code></pre></td></tr></table></figure></li>
<li><p>修改 <code>发布新文章</code> 的路由如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 发布新文章的路由</span><br><span class="hljs-comment">// upload.single() 是一个局部生效的中间件，用来解析 FormData 格式的表单数据</span><br><span class="hljs-comment">// 将文件类型的数据，解析并挂载到 req.file 属性中</span><br><span class="hljs-comment">// 将文本类型的数据，解析并挂载到 req.body 属性中</span><br>router.<span class="hljs-title function_">post</span>(<span class="hljs-string">&#x27;/add&#x27;</span>, upload.<span class="hljs-title function_">single</span>(<span class="hljs-string">&#x27;cover_img&#x27;</span>), article_handler.<span class="hljs-property">addArticle</span>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/article.js</code> 模块中的 <code>addArticle</code> 处理函数中，将 <code>multer</code> 解析出来的数据进行打印：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 发布新文章的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">addArticle</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(req.<span class="hljs-property">body</span>) <span class="hljs-comment">// 文本类型的数据</span><br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;--------分割线----------&#x27;</span>)<br>  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(req.<span class="hljs-property">file</span>) <span class="hljs-comment">// 文件类型的数据</span><br><br>  res.<span class="hljs-title function_">send</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="5-2-4-验证表单数据"><a href="#5-2-4-验证表单数据" class="headerlink" title="5.2.4 验证表单数据"></a>5.2.4 验证表单数据</h4><p><code>实现思路：通过 express-joi 自动验证 req.body 中的文本数据；通过 if 判断手动验证 req.file 中的文件数据；</code></p>
<ol>
<li><p>创建 <code>/schema/article.js</code> 验证规则模块，并初始化如下的代码结构：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入定义验证规则的模块</span><br><span class="hljs-keyword">const</span> joi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@hapi/joi&#x27;</span>)<br><br><span class="hljs-comment">// 定义 标题、分类Id、内容、发布状态 的验证规则</span><br><span class="hljs-keyword">const</span> title = joi.<span class="hljs-title function_">string</span>().required()<br><span class="hljs-keyword">const</span> cate_id = joi.<span class="hljs-title function_">number</span>().<span class="hljs-title function_">integer</span>().<span class="hljs-title function_">min</span>(<span class="hljs-number">1</span>).required()<br><span class="hljs-keyword">const</span> content = joi.<span class="hljs-title function_">string</span>().required().<span class="hljs-title function_">allow</span>(<span class="hljs-string">&#x27;&#x27;</span>)<br><span class="hljs-keyword">const</span> state = joi.<span class="hljs-title function_">string</span>().<span class="hljs-title function_">valid</span>(<span class="hljs-string">&#x27;已发布&#x27;</span>, <span class="hljs-string">&#x27;草稿&#x27;</span>).required()<br><br><span class="hljs-comment">// 验证规则对象 - 发布文章</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">add_article_schema</span> = &#123;<br>  <span class="hljs-attr">body</span>: &#123;<br>    title,<br>    cate_id,<br>    content,<br>    state,<br>  &#125;,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router/article.js</code> 模块中，导入需要的验证规则对象，并在路由中使用：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入验证数据的中间件</span><br><span class="hljs-keyword">const</span> expressJoi = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;@escook/express-joi&#x27;</span>)<br><span class="hljs-comment">// 导入文章的验证模块</span><br><span class="hljs-keyword">const</span> &#123; add_article_schema &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../schema/article&#x27;</span>)<br><br><span class="hljs-comment">// 发布新文章的路由</span><br><span class="hljs-comment">// 注意：在当前的路由中，先后使用了两个中间件：</span><br><span class="hljs-comment">//       先使用 multer 解析表单数据</span><br><span class="hljs-comment">//       再使用 expressJoi 对解析的表单数据进行验证</span><br>router.<span class="hljs-title function_">post</span>(<br>  <span class="hljs-string">&#x27;/add&#x27;</span>,<br>  upload.<span class="hljs-title function_">single</span>(<span class="hljs-string">&#x27;cover_img&#x27;</span>),<br>  <span class="hljs-title function_">expressJoi</span>(add_article_schema),<br>  article_handler.<span class="hljs-property">addArticle</span><br>)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>/router_handler/article.js</code> 模块中的 <code>addArticle</code> 处理函数中，通过 <code>if</code> 判断客户端是否提交了 <code>封面图片</code>：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 发布新文章的处理函数</span><br><span class="hljs-built_in">exports</span>.<span class="hljs-property">addArticle</span> = <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> &#123;<br>    <span class="hljs-comment">// 手动判断是否上传了文章封面</span><br>  <span class="hljs-keyword">if</span> (!req.<span class="hljs-property">file</span> || req.<span class="hljs-property">file</span>.<span class="hljs-property">fieldname</span> !== <span class="hljs-string">&#x27;cover_img&#x27;</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;文章封面是必选参数！&#x27;</span>)<br><br>  <span class="hljs-comment">// TODO：表单数据合法，继续后面的处理流程...</span><br>&#125;)<br></code></pre></td></tr></table></figure></li>
</ol>
<h4 id="5-2-5-实现发布文章的功能"><a href="#5-2-5-实现发布文章的功能" class="headerlink" title="5.2.5 实现发布文章的功能"></a>5.2.5 实现发布文章的功能</h4><ol>
<li><p>整理要插入数据库的文章信息对象：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入处理路径的 path 核心模块</span><br><span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;path&#x27;</span>)<br><br><span class="hljs-keyword">const</span> articleInfo = &#123;<br>  <span class="hljs-comment">// 标题、内容、状态、所属的分类Id</span><br>  ...req.<span class="hljs-property">body</span>,<br>  <span class="hljs-comment">// 文章封面在服务器端的存放路径</span><br>  <span class="hljs-attr">cover_img</span>: path.<span class="hljs-title function_">join</span>(<span class="hljs-string">&#x27;/uploads&#x27;</span>, req.<span class="hljs-property">file</span>.<span class="hljs-property">filename</span>),<br>  <span class="hljs-comment">// 文章发布时间</span><br>  <span class="hljs-attr">pub_date</span>: <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(),<br>  <span class="hljs-comment">// 文章作者的Id</span><br>  <span class="hljs-attr">author_id</span>: req.<span class="hljs-property">user</span>.<span class="hljs-property">id</span>,<br>&#125;<br></code></pre></td></tr></table></figure></li>
<li><p>定义发布文章的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-keyword">const</span> sql = <span class="hljs-string">`insert into ev_articles set ?`</span><br></code></pre></td></tr></table></figure></li>
<li><p>调用 <code>db.query()</code> 执行发布文章的 SQL 语句：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 导入数据库操作模块</span><br><span class="hljs-keyword">const</span> db = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;../db/index&#x27;</span>)<br><br><span class="hljs-comment">// 执行 SQL 语句</span><br>db.<span class="hljs-title function_">query</span>(sql, articleInfo, <span class="hljs-function">(<span class="hljs-params">err, results</span>) =&gt;</span> &#123;<br>  <span class="hljs-comment">// 执行 SQL 语句失败</span><br>  <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(err)<br><br>  <span class="hljs-comment">// 执行 SQL 语句成功，但是影响行数不等于 1</span><br>  <span class="hljs-keyword">if</span> (results.<span class="hljs-property">affectedRows</span> !== <span class="hljs-number">1</span>) <span class="hljs-keyword">return</span> res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;发布文章失败！&#x27;</span>)<br><br>  <span class="hljs-comment">// 发布文章成功</span><br>  res.<span class="hljs-title function_">cc</span>(<span class="hljs-string">&#x27;发布文章成功&#x27;</span>, <span class="hljs-number">0</span>)<br>&#125;)<br></code></pre></td></tr></table></figure></li>
<li><p>在 <code>app.js</code> 中，使用 <code>express.static()</code> 中间件，将 <code>uploads</code> 目录中的图片托管为静态资源：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs js"><span class="hljs-comment">// 托管静态资源文件</span><br>app.<span class="hljs-title function_">use</span>(<span class="hljs-string">&#x27;/uploads&#x27;</span>, express.<span class="hljs-title function_">static</span>(<span class="hljs-string">&#x27;./uploads&#x27;</span>))<br></code></pre></td></tr></table></figure></li>
</ol>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/%E5%89%8D%E7%AB%AF/" class="category-chain-item">前端</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/node/">#node</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>HeadLine</div>
      <div>http://dayu.com/2022/11/30/HeadLine/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>dayu</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2022年11月30日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/12/02/vue3%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/" title="vue3快速入门">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">vue3快速入门</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/11/27/react%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" title="react学习笔记">
                        <span class="hidden-mobile">react学习笔记</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
  <article id="comments" lazyload>
    
  <div id="valine"></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#valine', function() {
      Fluid.utils.createScript('https://lib.baomitu.com/valine/1.5.1/Valine.min.js', function() {
        var options = Object.assign(
          {"appId":"你的appId","appKey":"你的appKey","path":"window.location.pathname","placeholder":"留言仅限讨论，禁止广告等行为","avatar":"retro","meta":["nick","mail","link"],"requiredFields":[],"pageSize":10,"lang":"zh-CN","highlight":false,"recordIP":false,"serverURLs":"你的serverURLs","emojiCDN":null,"emojiMaps":null,"enableQQ":false},
          {
            el: "#valine",
            path: window.location.pathname
          }
        )
        new Valine(options);
        Fluid.utils.waitElementVisible('#valine .vcontent', () => {
          var imgSelector = '#valine .vcontent img:not(.vemoji)';
          Fluid.plugins.imageCaption(imgSelector);
          Fluid.plugins.fancyBox(imgSelector);
        })
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


  </article>


          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
    </div>
  
  
    <div class="statistics">
  
  

  
    
      <span id="busuanzi_container_site_pv" style="display: none">
        总访问量 
        <span id="busuanzi_value_site_pv"></span>
         次
      </span>
    
    
      <span id="busuanzi_container_site_uv" style="display: none">
        总访客数 
        <span id="busuanzi_value_site_uv"></span>
         人
      </span>
    
    
  
</div>

  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.11/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>

  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/love.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/xiaoxingxing.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/xiaoxuehua.js"></script>
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/caidai.js"></script>



<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
